package org.x.usermod.aspect;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.x.commonmod.config.BusinessException;
import org.x.commonmod.enums.RedisCache;
import org.x.commonmod.util.RedisKit;

import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class RedisCacheAspect {

    @Autowired
    RedisKit redisKit;

    @Pointcut("@annotation(org.x.commonmod.enums.RedisCache)")
    public void logPointcut() {}

    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        RedisCache redisCache = signature.getMethod().getAnnotation(RedisCache.class);

        String key = redisCache.key();
        int expire = redisCache.expire();
        TimeUnit timeUnit = redisCache.timeUnit();
        Class<?> value = redisCache.value();

        // key值需要 严格匹配 auth:user:{loginId} 这个规则
        if (!key.matches("auth:user:\\{loginId}")) {
            throw new BusinessException("RedisCache key 格式错误，必须是 auth:user:{loginId}");
        }

        // key  : auth:user:{loginId} loginId 从登录信息中获取
        String loginId = StpUtil.getLoginIdAsString();
        key = key.replace("{loginId}", loginId);

        // 从Redis中获取缓存
        Object cacheValue = redisKit.get(key);
        if (cacheValue != null) {
            Object object = JSON.parseObject(cacheValue.toString(), value);
            // 缓存命中，直接返回缓存值
            return object;
        }
        // 缓存未命中，执行方法并缓存结果
        try {
            Object result = joinPoint.proceed();
            redisKit.set(key, JSONObject.toJSONString(result), expire, timeUnit);
            return result;
        } catch (Throwable throwable) {
            throw new RuntimeException(throwable);
        }

    }

}
